#include "Imm.h"
#define ARG_LENGTH 4
//#define TEST_EVENTMAT

int ImmCodes::labelCounter = 0;
int BasicBlock::blockCounter = 0;
BasicBlockManager* BasicBlockManager::_manager = NULL;

vector<string>*
BasicBlock::getNextBlocks() {
	return &nextBlocksLabels;
}


void BasicBlockManager::removeEmptyBlocks(bool* updated){
	BasicBlockManager::getManager()->resetAllCode();

	vector<string> blocksToRemove;
	*updated = false;

	//Search for the number of times a block is used
	int* blockRefCounter = (int*) malloc(sizeof(int) * getAllBlocks()->size());
	memset(blockRefCounter, 0, sizeof(int) * getAllBlocks()->size());
	for (int i = 0; i < getAllBlocks()->size(); i++) {
		for (int j = 0; j < getAllBlocks()->at(i)->getNextBlocks()->size(); j++) {
			for (int k = 0; k < getAllBlocks()->size(); k++)
				if (getAllBlocks()->at(i)->getNextBlocks()->at(j)
						== getAllBlocks()->at(k)->getLabel())
					blockRefCounter[k]++;
		}
	}



	for (int i = 0; i < getAllBlocks()->size(); i++)
		if (blockRefCounter[i] == 0 && getAllBlocks()->at(i)->getLabel().substr(0, 1) == "L") {
			blocksToRemove.push_back(getAllBlocks()->at(i)->getLabel());
			*updated = true;
			//cout << getAllBlocks()->at(i)->getLabel() << " block is removed"<<endl;
		}

	for (int i = 0; i < blocksToRemove.size(); i++) {
		replaceBB(blocksToRemove.at(i));
		*updated = true;
	}

	//BasicBlockManager::getManager()->resetAllCode();

	free(blockRefCounter);
	BasicBlockManager::getManager()->resetAllCode();

}

/*
void BasicBlockManager::removeEmptyLabels(bool* updated){
	BasicBlockManager::getManager()->resetAllCode();

	vector<string> labelsToRemove;
	*updated = false;

	//Search for the number of times a block is used
	int* blockRefCounter = (int*) malloc(sizeof(int) * getAllBlocks()->size());
	memset(blockRefCounter, 0, sizeof(int) * getAllBlocks()->size());
	for (int i = 0; i < getAllBlocks()->size(); i++) {
		for (int j = 0; j < getAllBlocks()->at(i)->getNextBlocks()->size(); j++) {
			for (int k = 0; k < getAllBlocks()->size(); k++)
				if (getAllBlocks()->at(i)->getNextBlocks()->at(j)
						== getAllBlocks()->at(k)->getLabel())
					blockRefCounter[k]++;
		}
	}


	for (int i = 0; i < getAllBlocks()->size(); i++) {
		cout << "label: " << getAllBlocks()->at(i)->getLabel() << " used for "
				<< blockRefCounter[i] << " times " << endl;
	}

	for (int i = 0; i < getAllBlocks()->size(); i++)
		if (blockRefCounter[i] == 1) {
			for (int j = 0; j < getAllBlocks()->size(); j++) {
				if (getAllBlocks()->at(j)->getNextBlocks()->size() == 1
						&& getAllBlocks()->at(j)->getNextBlocks()->at(0)
								== getAllBlocks()->at(i)->getLabel()
						&& getAllBlocks()->at(j)->getLabel().substr(0, 1) == "L"
						&& getAllBlocks()->at(i)->getLabel().substr(0, 1) == "L"
								&& getAllBlocks()->at(j+1)->getLabel() == getAllBlocks()->at(i)->getLabel()) {
					cout << "\n---------->Combine block "
							<< getAllBlocks()->at(j)->getLabel() << " and "
							<< getAllBlocks()->at(i)->getLabel() << endl;
					labelsToRemove.push_back(getAllBlocks()->at(i)->getLabel());
					*updated = true;
				}
			}

		}

	removeLabelNode(&labelsToRemove);
	free(blockRefCounter);

	BasicBlockManager::getManager()->resetAllCode();

	free(blockRefCounter);
	//BasicBlockManager::getManager()->resetAllCode();

}


bool BasicBlockManager::confineBlocks(bool *updated) {
	BasicBlockManager::getManager()->resetAllCode();

	*updated = false;

	vector<string> labelsToRemove;
	vector<string> blocksToRemove;

/	for (int i = 0; i < getAllBlocks()->size(); i++) {
		cout << "label: " << getAllBlocks()->at(i)->getLabel() << endl;
		for (int j = 0; j < getAllBlocks()->at(i)->getNextBlocks()->size(); j++) {
			cout << "follower: " << getAllBlocks()->at(i)->getNextBlocks()->at(
					j) << endl;
		}
		cout << endl;
	}/

	//Search for the number of times a block is used
	int* blockRefCounter = (int*) malloc(sizeof(int) * getAllBlocks()->size());
	memset(blockRefCounter, 0, sizeof(int) * getAllBlocks()->size());
	for (int i = 0; i < getAllBlocks()->size(); i++) {
		for (int j = 0; j < getAllBlocks()->at(i)->getNextBlocks()->size(); j++) {
			for (int k = 0; k < getAllBlocks()->size(); k++)
				if (getAllBlocks()->at(i)->getNextBlocks()->at(j)
						== getAllBlocks()->at(k)->getLabel())
					blockRefCounter[k]++;
		}
	}

	//For those blocks used only once, search if they are the only next block
	for (int i = 0; i < getAllBlocks()->size(); i++)
		if (blockRefCounter[i] == 0 && getAllBlocks()->at(i)->getLabel() != "init_global" && getAllBlocks()->at(i)->get_code()->size() > 0 && getAllBlocks()->at(i)->get_code()->at(0)->getType() != ImmCode::ENTER)
			{blocksToRemove.push_back(getAllBlocks()->at(i)->getLabel());
			*updated = true;
			goto processdata;
			}
		else if (blockRefCounter[i] == 1) {
				for (int j = 0; j < getAllBlocks()->size(); j++) {
					if (getAllBlocks()->at(j)->getNextBlocks()->size() == 1
							&& getAllBlocks()->at(j)->getNextBlocks()->at(0)
									== getAllBlocks()->at(i)->getLabel()
							&& getAllBlocks()->at(j)->getLabel() != "init_global"
							&& getAllBlocks()->at(i)->getLabel() != "init_global"
									&& getAllBlocks()->at(j+1)->getLabel() == getAllBlocks()->at(i)->getLabel()) {
						cout << "\nCombine block "
								<< getAllBlocks()->at(j)->getLabel() << " and "
								<< getAllBlocks()->at(i)->getLabel() << endl;
						labelsToRemove.push_back(getAllBlocks()->at(i)->getLabel());
						*updated = true;
						goto processdata;
					}
				}

			}
processdata:;

		for (int i = 0; i < getAllBlocks()->size(); i++) {
	 cout << "label: " << getAllBlocks()->at(i)->getLabel() << " used for "
	 << blockRefCounter[i] << " times " << endl;
	 }


	removeLabelNode(&labelsToRemove);


	for (int i=0; i<blocksToRemove.size(); i++){
//		cout << blocksToRemove.at(i) << " block  is removed!!!\n\n";
		replaceBB(blocksToRemove.at(i));
		*updated = true;
	}

	free(blockRefCounter);
	BasicBlockManager::getManager()->resetAllCode();

	return false;
}
*/

void BasicBlockManager::removeLabelNode(vector<string>* labels){
	ImmCodes* codes = getCode();
	ImmCodes* out = new ImmCodes();

	for (int i=0; i<codes->count(); i++){
		if (codes->get_code()->at(i)->getType() == ImmCode::LABEL){

//			if (i==0 || codes->get_code()->at(i-1)->getType() == ImmCode::GOTO)
//				goto addInst;

			ostringstream os;
			void** opnd = (codes->get_code()->at(i)->get_opnd());
			unsigned int id = (long)opnd[0];
			string *name = (string*)opnd[1];
			if (name && name->length())
					os << *name;
			else
					os << "L" << id;

			for (int j=0; j<labels->size(); j++)
				if (os.str() == labels->at(j))
					goto nextInst;
		}
		addInst:;
		out->add(codes->get_code()->at(i));
		nextInst:;
	}

	resetAllCode(out);
}

BasicBlock*
BasicBlock::constantPropogation(bool* updated) {
	vector<ImmCode*>::iterator it = m_codes.begin();
	vector<ExprNode*> constantNodes;
	vector<string> variableWithConstantValue;

	BasicBlock* seBB = new BasicBlock(label);

	for (int i = 0; i < m_codes.size(); i++) {

		ImmCode* code = m_codes.at(i);
		if (!(*updated)) {
			//get the constant
			if (code->getType() == ImmCode::EXPR && code->get_subcode()
					== OpNode::ASSIGN) {
				ExprNode** opd = (ExprNode**) (code->get_opnd());
				 //|| opd[2] == NULL
				if (opd[1]->exprNodeType() == ExprNode::VALUE_NODE || opd[2] == NULL) {

					if (opd[1]->addrName() == opd[0]->addrName() && opd[2] == NULL){
						//*updated = true;
						continue;
					}

					for (int j=0; j<variableWithConstantValue.size(); j++){
						if (variableWithConstantValue.at(j) == opd[0]->addrName()){
							constantNodes.erase(constantNodes.begin()+j);
							variableWithConstantValue.erase(variableWithConstantValue.begin()+j);
							break;
						}
					}
					constantNodes.push_back((ValueNode*) opd[1]);
					variableWithConstantValue.push_back(opd[0]->addrName());
				}

			}

			//Substitute the constant
			switch (code->getType()) {
			case ImmCode::EXPR: {
				ExprNode** opd = (ExprNode**) (code->get_opnd());
				ExprNode* node1 = opd[1];
				ExprNode* node2 = opd[2];
				switch (code->get_subcode()) {
				case OpNode::PLUS:
				case OpNode::MINUS:
				case OpNode::MULT:
				case OpNode::DIV:
				case OpNode::MOD:
				case OpNode::EQ:
				case OpNode::NE:
				case OpNode::GT:
				case OpNode::LT:
				case OpNode::GE:
				case OpNode::LE:
				case OpNode::AND:
				case OpNode::OR:
				case OpNode::SHL:
				case OpNode::SHR:
					//available constant within the current basic block
					for (int i = 0; i < variableWithConstantValue.size(); i++) {
						if (variableWithConstantValue.at(i)
								== opd[1]->addrName()) {
							node1 = constantNodes.at(i);
							*updated = true;
						}
						if (opd[2] && variableWithConstantValue.at(i)
								== opd[2]->addrName()) {
							node2 = constantNodes.at(i);
							*updated = true;
						}
					}
					break;
				case OpNode::ASSIGN:
				case OpNode::UMINUS:
				case OpNode::NOT:
				case OpNode::BITNOT:
					for (int i = 0; i < variableWithConstantValue.size(); i++) {
						if (variableWithConstantValue.at(i)
								== opd[1]->addrName()) {
							node1 = constantNodes.at(i);
							*updated = true;
						}
					}
					break;

				case OpNode::BITAND:
				case OpNode::BITOR:
				case OpNode::BITXOR:
					for (int i = 0; i < variableWithConstantValue.size(); i++) {
						if (variableWithConstantValue.at(i)
								== opd[1]->addrName()) {
							node1 = constantNodes.at(i);
							*updated = true;
						}
					}
					break;

				default:

					break;
				}
				seBB->add(new ImmCode(code->getType(), code->get_subcode(),
						opd[0], node1, node2));

				break;
			}
			case ImmCode::IF_REL:
			case ImmCode::IF: {
				ExprNode** opd = (ExprNode**) (code->get_opnd());
				ExprNode* node1 = opd[1];
				ExprNode* node2 = opd[2];
				for (int i = 0; i < variableWithConstantValue.size(); i++) {
					if (variableWithConstantValue.at(i) == opd[1]->addrName()) {
						node1 = constantNodes.at(i);
						*updated = true;
					}
					if (opd[2] && variableWithConstantValue.at(i)
							== opd[2]->addrName()) {
						node2 = constantNodes.at(i);
						*updated = true;
					}
				}
				seBB->add(new ImmCode(code->getType(), code->get_subcode(),
						opd[0], node1, node2));
				break;
			}
/*			case ImmCode::PARAM: {
				ExprNode** opd = (ExprNode**) (code->get_opnd());
				ExprNode* param = opd[0];

				for (int i = 0; i < variableWithConstantValue.size(); i++) {
					if (variableWithConstantValue.at(i) == opd[0]->addrName()) {
						param = constantNodes.at(i);
						*updated = true;
						break;
					}
				}
				seBB->add(new ImmCode(code->getType(), code->get_subcode(),
						param));

				break;



			}*/

			default:
				seBB->add(code);
				break;
			}

		}

		else
			seBB->add(code);
	}
	return seBB;

}

vector<BasicBlock*>*
ImmCodes::divideBasicBlocks() {
	// TODO
	vector<ImmCode*>::iterator it = m_codes.begin();
	bool isNewBB = false;

	BasicBlock* oneBlock = BasicBlockManager::getManager()->getBlockWithLabel(
			"init_global");

	for (; it != m_codes.end(); it++) {

		if (((*it)->getType() != ImmCode::GOTO) && (*it)->getType()
				!= ImmCode::LABEL && (*it)->getType() != ImmCode::LEAVE) {
			isNewBB = false;
			oneBlock->add(*it);
			if ((*it)->getType() == ImmCode::IF_REL || (*it)->getType()
					== ImmCode::IF) {
				void** opnd = (*it)->get_opnd();
				//oneBlock->addNextBlock(BasicBlockManager::getManager()->getBlockWithLabel(((ImmCode*)(opnd[0]))->labelName()));
				oneBlock->addNextBlock(((ImmCode*) (opnd[0]))->labelName());
			}
		}
		else if ((*it)->getType() == ImmCode::LEAVE){
			oneBlock->add(*it);
			isNewBB = true;
		}
		else {
			if ((*it)->getType() == ImmCode::GOTO) {
				oneBlock->add(*it);
				void** opnd = (*it)->get_opnd();
				//oneBlock->addNextBlock(BasicBlockManager::getManager()->getBlockWithLabel(((ImmCode*)(opnd[0]))->labelName()));
				oneBlock->addNextBlock(((ImmCode*) (opnd[0]))->labelName());
				//oneBlock = BasicBlockManager::getManager()->getBlockWithLabel((*it)->labelName());
				isNewBB = true;

			} else if ((*it)->getType() == ImmCode::LABEL) {
				//oneBlock->addNextBlock(BasicBlockManager::getManager()->getBlockWithLabel((*it)->labelName()));
				if (!isNewBB)
					oneBlock->addNextBlock((*it)->labelName());
				isNewBB = false;
				oneBlock = BasicBlockManager::getManager()->getBlockWithLabel(
						(*it)->labelName());
			}

			//			if ((*it)->getType() == ImmCode::LABEL)
			//				oneBlock->add(*it);
		}
	}

	return BasicBlockManager::getManager()->getAllBlocks();
}

BasicBlock* BasicBlock::iterativeDataFlowAnalysis() {
	bool updated1 = false, updated2 = false, updated3 = false;
	bool updated4 = false;

	BasicBlock* temp = this;			

	do{
		updated1 = false; updated2 = false; updated3 = false;
		
		temp = temp->liveVariables(&updated1);
		temp = temp->reachingDefinitions(&updated2);
		temp = temp->availableExpressions(&updated3);

	}while(updated1 || updated2 || updated3);

	return temp;
}

BasicBlock* BasicBlock::liveVariables(bool* updated=false){
	vector <ImmCode*>::iterator it = ImmCodes::m_codes.begin();
        vector <ImmCode*>::iterator it_temp;
	BasicBlock* seBB = new BasicBlock(label);
        bool flag;
        string op;

	vector<string>* nextBlocks = BasicBlockManager::getManager()->getBlockWithLabel(label)->getNextBlocks();
	int nextBlockSize = nextBlocks->size();

        for(; it!=ImmCodes::m_codes.end();it++){//start search of variables for liveness
		
		if(getLabel() == "init_global")//special condition for initial block "init_global"(all global variables are live)
			seBB->add(*it);

	        else if ((*it)->getType() == ImmCode::EXPR &&
		    (*it)->get_subcode() == OpNode::ASSIGN){

			ExprNode** opd = (ExprNode**)((*it)->get_opnd());
                        op = opd[0]->addrName();//current variable

                        it_temp = it;
                        flag = false;

                        for(it+=1; it!=ImmCodes::m_codes.end(); it++){//search for use in the current block
                                ExprNode** opd2 = (ExprNode**)((*it)->get_opnd()); 

				switch((*it)->getType()){
					case ImmCode::EXPR:
					case ImmCode::IF:
					case ImmCode::IF_REL:
						if((opd2[1]!=NULL && op == opd2[1]->addrName()) ||
                                   		   (opd2[2]!=NULL && op == opd2[2]->addrName()))//this means it is used in the current block
                                        		flag = true;
                                        	break;

					case ImmCode::PARAM:
					case ImmCode::LEAVE:
						if(opd2[0]!=NULL && op == opd2[0]->addrName())
							flag = true;
						break;
				}
                        }
			if(flag){//So it is live
                        	seBB->add(*it_temp); 
			}
                        else{//search for its use in the next blocks of the current block
				if(nextBlockSize > 0){
					//there are next blocks which can be reached from this block
					
					processedLabels.clear();
					//processedLabels.push_back(label);
					vector<string>::iterator nextLabel = nextBlocks->begin(); 
					for(; nextLabel!=nextBlocks->end(); nextLabel++){
						if(!isProcessed(*nextLabel)){
							if(checkVariableUseInNextBlocks(op, *nextLabel)){
								flag = true; 
								break;
							}
						}
					}
				}

				if(flag) seBB->add(*it_temp); //then variable is live
				else *updated = true; //else it is dead
			}
			it = it_temp;	
		}
		else seBB->add(*it);
	}
	return seBB;
}

bool BasicBlock::isProcessed(string label){

	int size = processedLabels.size();

	for(int i=0; i<size; i++)
		if(processedLabels.at(i) == label) return true;

	return false;
}

bool BasicBlock::checkVariableUseInNextBlocks(string op, string label){

	bool flag = false;
	BasicBlock* nextBlock = BasicBlockManager::getManager()->getBlockWithLabel(label);
	vector<ImmCode*>::iterator nextCode = nextBlock->get_code()->begin();//get the code of the next block
	processedLabels.push_back(label);

	for(; nextCode!=nextBlock->get_code()->end(); nextCode++){
		ExprNode** opdNext = (ExprNode**)((*nextCode)->get_opnd());

				switch((*nextCode)->getType()){
					case ImmCode::EXPR:
					case ImmCode::IF:
					case ImmCode::IF_REL:
						if((opdNext[1]!=NULL && op == opdNext[1]->addrName()) ||
                                   		   (opdNext[2]!=NULL && op == opdNext[2]->addrName()))//this means it is used in the current block
                                        		return true;
                                        	break;

					case ImmCode::PARAM:
					case ImmCode::LEAVE:
						if(opdNext[0]!=NULL && op == opdNext[0]->addrName())
							return true;
						break;
				}
		if(!flag && nextBlock->getNextBlocks()->size() > 0) 
			flag = true;
	}

	if(flag){
		vector<string>::iterator nextLabel = nextBlock->getNextBlocks()->begin();
		for(; nextLabel!=nextBlock->getNextBlocks()->end(); nextLabel++){
			if(!isProcessed(*nextLabel)){
				if(checkVariableUseInNextBlocks(op, *nextLabel)){
					return true; 
				}
			}
		}
	}
	return false;								
}

bool BasicBlock::checkVariableUseBeforeDef(string op, string label){

	bool flag = false, flag2 = false;
	BasicBlock* nextBlock = BasicBlockManager::getManager()->getBlockWithLabel(label);
	vector<ImmCode*>::iterator nextCode = nextBlock->get_code()->begin();//get the code of the next block
	processedLabels.push_back(label);

	for(; nextCode!=nextBlock->get_code()->end(); nextCode++){
		ExprNode** opdNext = (ExprNode**)((*nextCode)->get_opnd());

				switch((*nextCode)->getType()){//USE before DEF
					case ImmCode::EXPR:
					case ImmCode::IF:
					case ImmCode::IF_REL:
						if((opdNext[1]!=NULL && op == opdNext[1]->addrName()) ||
                                   		   (opdNext[2]!=NULL && op == opdNext[2]->addrName()))
							if(!flag)//not DEF yet ==> USE before DEF
                                        			return true;
                                        	break;

					case ImmCode::PARAM:
					case ImmCode::LEAVE:
						if(opdNext[0]!=NULL && op == opdNext[0]->addrName())
							if(!flag)//not DEF yet => USE before DEF
								return true;
						break;
				}
				if ((*nextCode)->getType() == ImmCode::EXPR &&
		    		    (*nextCode)->get_subcode() == OpNode::ASSIGN &&
				     op == opdNext[0]->addrName()){//DEF before USE
					flag = true;
					continue;				
				}
		if(!flag2 && nextBlock->getNextBlocks()->size() > 0) 
			flag2 = true;
	}

	if(flag2){
		vector<string>::iterator nextLabel = nextBlock->getNextBlocks()->begin();
		for(; nextLabel!=nextBlock->getNextBlocks()->end(); nextLabel++){
			if(!isProcessed(*nextLabel)){
				if(checkVariableUseBeforeDef(op, *nextLabel)){
					return true; 
				}
			}

		}
	}
	return false;								
}


BasicBlock* BasicBlock::reachingDefinitions(bool* updated=false){
	vector <ImmCode*>::iterator it = ImmCodes::m_codes.begin();
	vector <ImmCode*>::iterator it_temp;
	BasicBlock* seBB = new BasicBlock(label);
	bool flag,flag2,flag3;
	string op;

	vector<string>* nextBlocks = BasicBlockManager::getManager()->getBlockWithLabel(label)->getNextBlocks();
	int nextBlockSize = nextBlocks->size();

	for(; it!=ImmCodes::m_codes.end();it++){
		if(getLabel() == "init_global")//special condition for initial block "init_global"(all definitions reach)
			seBB->add(*it);
		
		else if ((*it)->getType() == ImmCode::EXPR &&
		         (*it)->get_subcode() == OpNode::ASSIGN){//only for definitions of variables

			ExprNode** opd = (ExprNode**)((*it)->get_opnd());
			op = opd[0]->addrName();//this is the initial definition of a variable

			it_temp = it;
			flag = false; flag2 = false; flag3 = false;

			for(it+=1; it!=ImmCodes::m_codes.end(); it++){//search for its use or redefinition in current block
                                ExprNode** opd2 = (ExprNode**)((*it)->get_opnd());

				switch((*it)->getType()){
					case ImmCode::EXPR:
					case ImmCode::IF:
					case ImmCode::IF_REL:
						if((opd2[1]!=NULL && op == opd2[1]->addrName()) ||
                                   		   (opd2[2]!=NULL && op == opd2[2]->addrName()))//USE before DEF
                                        		flag = true;
                                        	break;

					case ImmCode::PARAM:
					case ImmCode::LEAVE:
						if(opd2[0]!=NULL && op == opd2[0]->addrName())
							flag = true;
						break;
				}
				if(flag) break;

				else if ((*it)->getType() == ImmCode::EXPR &&
		    		         (*it)->get_subcode() == OpNode::ASSIGN &&
				          op == opd2[0]->addrName()){//DEF before USE
						flag2 = true;						
						break;				
				}
			}
			if(flag) seBB->add(*it_temp); //it is used before redefinition in the current block ==> it is live
			else if(flag2) *updated = true; //it is redefined before use in the current block ==> it is dead
			else{//not used or redefined in current block
				
				if(nextBlockSize > 0){//there are next blocks which can be reached from this block
				//now we need to check if there is any block where it is used before redefinition. If yes then it is live else dead.
					
					processedLabels.clear();
					//processedLabels.push_back(label);
					vector<string>::iterator nextLabel = nextBlocks->begin(); 
					for(; nextLabel!=nextBlocks->end(); nextLabel++){
						if(!isProcessed(*nextLabel)){
							if(checkVariableUseBeforeDef(op, *nextLabel)){//not used before def in any block
								flag3 = true; 
								break;
							}
						}
					}
					if(flag3) seBB->add(*it_temp); //it is used before redefinition in some block ==> it is live
					else *updated = true; //else ==> it is dead
				}
				else *updated = true; //else ==> it is dead
			}
			it = it_temp;
		}
		else seBB->add(*it);
	}
	return seBB;
}


int BasicBlock::isStatementAdded(int stmnt){
	
	int size = addedStatements.size();

	for(int i=0; i<size; i++)
		if(addedStatements.at(i) == stmnt) return i;
	return -1;
}


BasicBlock* BasicBlock::availableExpressions(bool* updated=false){
	vector <ImmCode*>::iterator it = ImmCodes::m_codes.begin();
	vector <ImmCode*>::iterator it_temp;
	BasicBlock* seBB = new BasicBlock(label);

	OpNode::OpCode code;
	int stmnt=0, newstmnt=0, index=0;


	if(getLabel() == "init_global"){//special condition for initial block "init_global"(no expression is available)
		for(; it!=ImmCodes::m_codes.end();it++)		
			seBB->add(*it);		
		return seBB;
	}

	addedStatements.clear();
	for(; it!=ImmCodes::m_codes.end();it++){
		stmnt+=1;
		
		if ((*it)->getType() == ImmCode::EXPR){

			ExprNode** opd = (ExprNode**)((*it)->get_opnd());

			code = (*it)->get_subcode(); //operator
	
			it_temp = it;
			newstmnt=0;

			for(it+=1; it!=ImmCodes::m_codes.end(); it++){//search for use of expression in current block
				newstmnt+=1;

				if ((*it)->getType() != ImmCode::EXPR) continue;

                                ExprNode** newopd = (ExprNode**)((*it)->get_opnd());
				
				if((opd[0]!=NULL && newopd[0]->addrName() == opd[0]->addrName()) || 
				   (opd[1]!=NULL && newopd[0]->addrName() == opd[1]->addrName()) || 
				   (opd[2]!=NULL && newopd[0]->addrName() == opd[2]->addrName())) //variables of expression redefined
					 break;



				if(newopd[1]->addrName()==opd[1]->addrName() && 
				   (opd[2]!=NULL && newopd[2] && newopd[2]->addrName()==opd[2]->addrName()) &&
				   (*it)->get_subcode()==code){
					
					addedStatements.push_back(stmnt+newstmnt);

					expressionList.push_back(new ImmCode((*it)->getType(), OpNode::ASSIGN, newopd[0], opd[0], 0));

				}
			}
			it = it_temp;
		}
	}

	//propagate the available expression data
	stmnt=0;
	it = ImmCodes::m_codes.begin();
	for(; it!=ImmCodes::m_codes.end();it++){
		stmnt += 1;

		index = isStatementAdded(stmnt);

		if(index == -1) seBB->add(*it);
		else{
			seBB->add(expressionList.at(index));
			*updated = true;
		}
	}
	return seBB;
}
